package com.jeremyaburns.oddio.tracker 
{
	import adobe.utils.CustomActions;
	import com.jeremyaburns.oddio.Instrument;
	import com.jeremyaburns.oddio.Song;
	import com.jeremyaburns.oddio.Track;
	import com.jeremyaburns.oddio.tracker.OTKeyboard;
	import com.jeremyaburns.oddio.TrackNote;
	import com.jeremyaburns.Vector2D;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.ui.Keyboard;
	import flash.utils.Timer;

	// This Sprite is the top-level class for the OddioTracker application.
	// Instantiate it and add it to the DisplayList, and you have a fully functional
	// instance of the app.  Aside from the inhereted Sprite interface, the important
	// public methods are:
	//   resize( width, height ) => Change the effective viewport size.
	//   dispose()               => Call this before you null your reference to
	//                              make sure everything get collected.
	public class OddioTracker extends Sprite
	{
		// The Oddio song we're editing.
		private var song :Song;
		
		// The components the user will interact with. They extend Sprite
		// and live on the display list as children of OddioTracker.
		private var keyboard    :OTKeyboard;
		private var noteboard   :OTNoteboard;
		private var waveEditor  :OTWaveEditor;
		private var instruments :OTInstrumentList;
		private var tracks      :OTTrackList;
		
				
		
		public function OddioTracker( width:Number, height:Number ) 
		{			
			// Create a new Song with default tempo, and add to it a single
			// track with a default instrument.
			song = new Song();
			song.instruments.push( new Instrument );
			song.tracks.push( new Track );
			song.tracks[0].instrument = song.instruments[0];
			
		//	song.instruments.push( new Track( new 
		//	song.tracks.push( new Track( new Instrument ) );
			
			// Create the keyboard and listen for clicks.
			keyboard = new OTKeyboard();
			keyboard.addEventListener( OTKeyboard.CLICK, keyboard_click );
			
			// The main note placing area.  This component is responsible for camera control.
			// When the camera moves, this guy fires an event so other components like the
			// keyboard can align themselves properly.
			noteboard = new OTNoteboard();
			noteboard.x = OTStyle.keyWidth;
			noteboard.addEventListener( OTNoteboard.PLAY_NOTE,   noteboard_playNote   );
			noteboard.addEventListener( OTNoteboard.MOVE_CAMERA, noteboard_moveCamera );
			
			// The instrument waveform editor tool.
			waveEditor = new OTWaveEditor( song );
			waveEditor.addEventListener( Event.COMPLETE, waveEditor_complete );
			waveEditor.visible = false;
			
			// Allows the user to select and edit instruments.
			instruments = new OTInstrumentList( song );
			instruments.addEventListener( OTInstrumentList.EVENT_CLICK_TILE, instruments_clickTile );
			
			// Track selector.
			tracks = new OTTrackList( song );
			
			// Populate the display list.
			addChild( noteboard   );
			addChild( keyboard    );
			addChild( instruments );
			addChild( tracks      );
			addChild( waveEditor  );
			
			// Set the default viewport width and height.
			resize( width, height );
		}
		
		
		// This function can be called to change the effective viewport of the app.
		public function resize( width:Number, height:Number ) :void
		{
			noteboard.resize( width, height );
			waveEditor.x = width  / 2;
			waveEditor.y = height / 2;
			instruments.x = width - instruments.width;
			instruments.resize( height / 2 );
			tracks.x = width - tracks.width;
			tracks.y = height/2;
			tracks.resize( height / 2 );
		}
		
		
		public function dispose() :void
		{
			
		}
		
		
		
		private function instruments_clickTile( e:OTEvent ) :void
		{
			waveEditor.show( int(e.data) );
		}
		
		private function waveEditor_complete( e:Event ) :void
		{
			waveEditor.hide();
			instruments.refreshTile( waveEditor.instrumentIndex );
		}
		
		
		private function this_addedToStage( e:Event ) :void
		{
			stage.addEventListener( KeyboardEvent.KEY_DOWN, stage_keyDown );
			stage.addEventListener( Event.RESIZE, stage_resize );
			stage_resize( null );
		}
		private function this_removedFromStage( e:Event ) :void
		{
			stage.removeEventListener( KeyboardEvent.KEY_DOWN, stage_keyDown );
			stage.removeEventListener( Event.RESIZE, stage_resize );
		}
		private function stage_resize( e:Event ) :void
		{
			
		}
		
		private function stage_keyDown( e:KeyboardEvent ) :void
		{
			if( e.keyCode != Keyboard.DELETE ) {
				if( e.keyCode == Keyboard.LEFT ) {
					waveEditor.visible = true;
				}
				return;
			}
			
			song.tracks[0].removeAllNotes();
			var notes :Vector.<OTNote> = noteboard.getNotes();
			for( var i:int = 0 ; i < notes.length ; ++i ) {
				song.tracks[0].addNote( notes[i].getTrackNote() );
			}
			
			song.play();
			addEventListener( Event.ENTER_FRAME, enterFrame_songPlaying );
		}
		
		private function enterFrame_songPlaying( e:Event ) :void
		{
			noteboard.playheadIndex = song.playhead;
		}
		
		
		private function noteboard_moveCamera( e:OTEvent ) :void
		{
			keyboard.y = -(e.data as Vector2D).y;
		}
		
		private function noteboard_playNote( e:OTEvent ) :void { testNote( int(e.data) ); }
		private function keyboard_click(    e:OTEvent ) :void { testNote( int(e.data) ); }
		
		private function testNote( pitch:int ) :void
		{
			if( song.tracks.length > 0 )
			song.tracks[0].instrument.playSingleNote( pitch );
		}
	}
}